共计2379个字符,预计需要花费6分钟才能阅读完成。
题目
题目给出了源代码,并且非常精简的代码:
from Crypto.Util.number import bytes_to_long
import random
flag = b"H&NCTF{}"
btl = str(bytes_to_long(flag))
lowercase = '0123456789'
uppercase = '7***4****5'
table = ''.maketrans(lowercase, uppercase)
new_flag = btl.translate(table)
n = 2 ** 512
m = random.randint(2, n - 1) | 1
c = pow(m, int(new_flag), n)
print('m = ' + str(m))
print('c = ' + str(c))
# m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
# c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399
分析
flag 先转换成了整数,然后对整数进行字典映射变换,得到 new_flag。其中已经知道 0->7、4->4、9->5,那么这里肯定要暴力求解的。变换后的整数 new_flag 经过以下数学公式:
c = m^{new\_flag} \; mod \; n
最终得到结果,并且根据注释已知 $$c,m,n$$,求 new_flag。
思路
由前面分析知道,这是一个 离散对数问题 ,可以用 SageMath 工具来求解,代码如下:
n = 2**512
m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399
# 创建模 n 的整数环
R = Zmod(n)
# 将 m 和 c 转换为环 R 中的元素
m = R(m)
c = R(c)
# 计算 m 在乘法群 (Z/nZ)* 中的阶
# 最小正整数 k 使得 m^k ≡ 1 mod n
ord = m.multiplicative_order()
new_flag = discrete_log(c, m, ord=ord)
print(f"new_flag = {new_flag}")
得到 new_flag 为 3282248010524512146638712359816289396373430161050484501341123570760619381019795910712610762203934445754701
。
接着暴力求解,遍历所有映射组合即可,代码:
from Crypto.Util.number import long_to_bytes
from itertools import permutations
new_flag = "3282248010524512146638712359816289396373430161050484501341123570760619381019795910712610762203934445754701"
lowercase = "0123456789"
# 需要暴力求解的位置
positions_to_fill = [1, 2, 3, 5, 6, 7, 8]
available_digits = [d for d in "0123456789" if d not in ["7", "4", "5"]]
# 暴力枚举所有可能的映射组合
for perm in permutations(available_digits, len(positions_to_fill)):
# uppercase 组合
uppercase_list = [""] * 10
uppercase_list[0] = "7" # 0 -> 7
uppercase_list[4] = "4" # 4 -> 4
uppercase_list[9] = "5" # 9 -> 5
for idx, digit in zip(positions_to_fill, perm):
uppercase_list[idx] = digit
uppercase = "".join(uppercase_list)
# 通过逆映射恢复原始字符串
table = str.maketrans(uppercase, lowercase)
flag = new_flag.translate(table)
try:
flag = long_to_bytes(int(flag))
print(flag.decode("gbk"))
# 检测是否为 flag
if flag.startswith(b"H&NCTF{") and flag.endswith(b"}"):
print(f"Flag: {flag.decode()}")
break
except Exception as e:
pass
得到 flag 为 H&NCTF{cut_cut_rrioajtfijrwegeriogjiireigji}
。
正文完